#include <stdio.h>
#include <opencv2/opencv.hpp>

void draw_and_fill_polygon(cv::Mat& image, const std::vector<cv::Point>& points, cv::Scalar line_color, cv::Scalar fill_color)
{
    // cv::fillPoly() 运行会报错
    cv::fillConvexPoly(image, points, fill_color);
    const int thickness = 2;
    cv::polylines(image, points, true, line_color, thickness);
}

void draw_and_fill_triangle(cv::Mat& image, cv::Scalar fill_color, cv::Point A, cv::Point B, cv::Point C)
{
    std::vector<cv::Point> points;
    points.push_back(A);
    points.push_back(B);
    points.push_back(C);

    cv::Scalar line_color(0);
    draw_and_fill_polygon(image, points, line_color, fill_color);
}

void draw_and_fill_rectangle(cv::Mat& image, cv::Scalar fill_color, cv::Point A, cv::Point B, cv::Point C, cv::Point D)
{
    std::vector<cv::Point> points;
    points.push_back(A);
    points.push_back(B);
    points.push_back(C);
    points.push_back(D);

    cv::Scalar line_color(0);
    draw_and_fill_polygon(image, points, line_color, fill_color);
}

cv::Scalar create_color(int hex)
{
    int b = hex / 65536;
    int g = (hex % 65536) / 256;
    int r = hex % 256;
    return cv::Scalar(b, g, r);
}

float degree_to_rad(float x)
{
    #define PI_DIV_180 (0.017453292519943296)
    return x * PI_DIV_180;
}

int main()
{
    printf("Hello, World!\n");

    cv::Size size;
    size.width = 800;
    size.height = 800;
    cv::Mat image(size, CV_8UC3);
    image = cv::Scalar(255, 255, 255);

    // draw 2
    if(0)
    {
        std::vector<cv::Point> points;
        // Point(x, y)
        cv::Point C(200, 300);
        cv::Point B(300, 400);
        cv::Point A(200, 400);
        cv::Scalar fill_color(0, 0, 255);
        draw_and_fill_triangle(image, fill_color, A, B, C);
    }

    const int unit = 100;
    cv::Scalar yellow = create_color(0xffff00);
    cv::Scalar pink = create_color(0xff00ff);
    cv::Scalar green = create_color(0x92d050);
    cv::Scalar purple = create_color(0x8b00ff);
    cv::Scalar blue = create_color(0x00b0f0);
    cv::Scalar red = create_color(0xff0000);
    cv::Scalar orange = create_color(0xffa500);
    int offx;
    int offy;

    std::vector<cv::Point> points;

    // K I L
    cv::Point K(400, 100);

    offy = unit * sqrt(2.0);
    cv::Point I(K.x, K.y + offy);

    offy = unit * sqrt(2.0) / 2;
    offx = offy;
    cv::Point L(K.x + offx, K.y + offy);

    draw_and_fill_triangle(image, yellow, K, I, L);

    // J H L
    cv::Point J(L.x + offx, K.y);
    offy = unit * sqrt(2.0);
    cv::Point H(L.x + offx, J.y + offy);
    draw_and_fill_triangle(image, pink, J, H, L);

    // I L H G
    offy = unit * sqrt(2.0);
    cv::Point G(L.x, L.y + offy);
    draw_and_fill_rectangle(image, green, I, L, H, G);

    // G F E
    offx = unit;
    offy = unit;
    cv::Point F(G.x + offx, G.y + offy);

    offy = unit * 2;
    cv::Point E(G.x, G.y + offy);

    draw_and_fill_triangle(image, purple, G, F, E);

    // G C D
    offx = 2 * unit * sqrt(2.0) / 2;
    offy = offx;
    cv::Point C(G.x - offx, G.y + offy);

    offy = 2 * unit * sqrt(2.0);
    cv::Point D(G.x, G.y + offy);

    draw_and_fill_triangle(image, blue, G, C, D);

    // C A B
    offy = 2 * unit;
    cv::Point A(C.x, C.y + offy);

    offx = 2 * unit;
    offy = 2 * unit;
    cv::Point B(C.x + offx, C.y + offy);

    draw_and_fill_triangle(image, red, C, A, B);

    // M A N P
    float y = unit / cos(degree_to_rad(22.5));
    offy = y * sqrt(2.0) / 2;
    offx = offy;
    cv::Point M(A.x - offx, A.y - offy);

    offx = y;
    cv::Point N(A.x - offx, A.y);

    cv::Point P(M.x - offx, M.y);

    draw_and_fill_rectangle(image, orange, M, A, N, P);

    cv::cvtColor(image, image, cv::COLOR_BGR2RGB);
    cv::imshow("image", image);
    cv::waitKey(0);

    cv::imwrite("result.png", image);

    return 0;
}

